package com.share.common.utils;

import com.share.common.enums.ContentTypeEnum;
import io.minio.*;
import io.minio.messages.DeleteError;
import io.minio.messages.DeleteObject;
import io.minio.messages.Item;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Minio 默认api addres 的端口是9000，浏览器访问9000端口时，会跳转到控制台端口
 */
@Slf4j
public class MinioUtil {
    final static String endpoint = "http://minio.snyq.ltd:9000";
    final static String BUCKET_NAME = "share";
    final static String accessKey = "Sbi6g1ViCo48YauS";
    final static String secretKey = "XsirUh2Rs9q1MCmBkjfnMLGac7yYZ1ce";

    private static MinioClient minioClient;

    //默认初始化
    static {
        minioClient = getMinioClient(endpoint, accessKey, secretKey);
    }

    /**
     * 给外部一个初始化的接口
     *
     * @param endpoint
     * @param accessKey
     * @param secretKey
     * @return
     */
    public static MinioClient getMinioClient(String endpoint, String accessKey, String secretKey) {
        try {
            return MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build();
        } catch (Exception e) {
            log.error("minio初始化失败", e);
            return null;
        }
    }

    /**
     * 创建bucket
     *
     * @param bucketName bucket名称
     */
    public static boolean createBucket(String bucketName) {
        try {
            if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
            }
            return true;
        } catch (Exception e) {
            log.error("bucket创建失败", e);
            return false;
        }
    }

    /**
     * 上传本地文件
     *
     * @param minioFileName minio上面的存储名字
     * @param localFileName 本地文件路径
     */
    public static String uploadLocalFile(String minioFileName, String localFileName) {
        return uploadLocalFile(BUCKET_NAME, minioFileName, localFileName);
    }

    /**
     * 上传本地文件
     *
     * @param minioFileName minio上面的存储名字
     * @param localFileName 本地文件路径
     */
    public static String uploadLocalFile(String bucketName, String minioFileName, String localFileName) {
        try {
            String contentType = ContentTypeEnum.getContentType(localFileName);
            UploadObjectArgs uploadObjectArgs = UploadObjectArgs.builder().bucket(bucketName).object(minioFileName)
                    .filename(localFileName).contentType(contentType).build();
            minioClient.uploadObject(uploadObjectArgs);
            return bucketName + (minioFileName.startsWith("/") ? minioFileName : "/" + minioFileName);
        } catch (Exception e) {
            log.error("minio文件上传异常", e);
            return null;
        }
    }

    //上传文件 返回文件相对路径
    public static String uploadFile(String minioFileName, String contentStr) {
        return uploadFile(BUCKET_NAME, minioFileName, contentStr.getBytes(StandardCharsets.UTF_8), null, null);
    }

    //上传文件 返回文件相对路径 /$BUCKET_NAME+minioFileName
    public static String uploadFile(String minioFileName, byte[] contentByte) {
        return uploadFile(BUCKET_NAME, minioFileName, contentByte, null, null);
    }

    //上传文件 返回文件相对路径 /$BUCKET_NAME+minioFileName
    private static String uploadFile(String bucketName, String minioFileName, byte[] contentByte, String contentType, Integer partSize) {
        int length = contentByte.length;
        ByteArrayInputStream inputStream = new ByteArrayInputStream(contentByte);
        return uploadFile(bucketName, minioFileName, inputStream, contentType, length, partSize);
    }

    //上传文件 返回文件相对路径  /$BUCKET_NAME+minioFileName
    private static String uploadFile(String bucketName, String minioFileName, InputStream inputStream, String contentType, int length, Integer partSize) {
        try {
            PutObjectArgs.Builder object = PutObjectArgs.builder().bucket(bucketName).object(minioFileName);

            if (partSize == null || partSize < 1 || partSize > 1024 * 1024) {
                partSize = -1;
            }

            object.stream(inputStream, length, partSize);
            //通过文件名字后缀,得到contentType
            if (StringUtils.isBlank(contentType)) {
                contentType = ContentTypeEnum.getContentType(minioFileName);
                if (StringUtils.isNotBlank(contentType)) {
                    object.contentType(contentType);
                }
            }

            PutObjectArgs putObjct = object.build();
            minioClient.putObject(putObjct);
            return "/" + bucketName + (minioFileName.startsWith("/") ? minioFileName : "/" + minioFileName);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("minio文件上传异常", e);
            return null;
        }
    }

    /**
     * 删除文件
     *
     * @param bucketName
     * @param minioFileNameList
     * @return
     */
    public static int deleteFiles(String bucketName, List<String> minioFileNameList) {
        AtomicInteger re = new AtomicInteger();
        if (CollectionUtils.isEmpty(minioFileNameList)) {
            return -1;
        }

        List<DeleteObject> delList = new LinkedList<>();
        minioFileNameList.stream().forEach(e -> {
            if (StringUtils.isNotBlank(e)) {
                re.getAndIncrement();
                delList.add(new DeleteObject(e));
            }
        });

        RemoveObjectsArgs build = RemoveObjectsArgs.builder().bucket(bucketName).objects(delList).build();
        Iterable<Result<DeleteError>> results = minioClient.removeObjects(build);

        //下面的 迭代必须写,否则文件无法删除,很奇怪的问题(iterator.hasNext()必须要有)
        Iterator<Result<DeleteError>> iterator = results.iterator();
        while (iterator.hasNext()) {
            Result<DeleteError> next = iterator.next();
            try {
                String s = next.get().objectName();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return re.get();
    }

    public static int deleteFiles(List<String> fileList) {
        return deleteFiles(BUCKET_NAME, fileList);
    }

    public static int deleteFiles(String... fileNames) {
        if (fileNames != null && fileNames.length > 0) {
            List<String> list = Arrays.asList(fileNames);
            return deleteFiles(BUCKET_NAME, list);
        }
        return -1;
    }

    public static List<String> listFilesByPrefix(String dir) {
        return listFilesByPrefix(BUCKET_NAME, dir, false);
    }

    public static List<String> listFilesByPrefix(String dir, Boolean isDeep) {
        return listFilesByPrefix(BUCKET_NAME, dir, isDeep);
    }

    public static int deleteFilesWithPrefix(String prefix) {
        return deleteFilesWithPrefix(BUCKET_NAME, prefix);
    }

    public static int deleteFilesWithPrefix(String bucketName, String prefix) {
        if (StringUtils.isEmpty(prefix)) {
            return -1;
        }

        List<String> fileList = new LinkedList<>();

        //开始查询
        ListObjectsArgs build = ListObjectsArgs.builder().bucket(bucketName).prefix(prefix).build();
        Iterable<Result<Item>> results = minioClient.listObjects(build);
        Iterator<Result<Item>> iterator = results.iterator();
        while (iterator.hasNext()) {
            Result<Item> next = iterator.next();
            try {
                String s = next.get().objectName();
                fileList.add(s);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        //开始删除
        return deleteFiles(fileList);
    }

    /**
     * 查询目录下的 需要带上 /
     *
     * @param bucketName
     * @param prefix     输入不存在的名字 返回是空
     * @return
     */
    public static List<String> listFilesByPrefix(String bucketName, String prefix, Boolean isDeep) {
        List<String> fileList = new LinkedList<>();
        if (StringUtils.isEmpty(prefix)) {
            return null;
        }

        //开始查询
        ListObjectsArgs build = ListObjectsArgs.builder().bucket(bucketName).prefix(prefix).build();
        Iterable<Result<Item>> results = minioClient.listObjects(build);
        Iterator<Result<Item>> iterator = results.iterator();
        while (iterator.hasNext()) {
            Result<Item> next = iterator.next();
            try {
                Item item = next.get();
                String fileName = item.objectName();
                if (item.isDir()) {
                    if (isDeep != null && isDeep) {
                        //递归调用
                        List<String> tmpList = listFilesByPrefix(bucketName, fileName, isDeep);
                        if (!CollectionUtils.isEmpty(tmpList)) {
                            fileList.addAll(tmpList);
                        }
                    }
                } else {
                    fileList.add(fileName);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return fileList;
    }

    public static void main(String[] args) {
        List<String> list = listFilesByPrefix("/image/20", true);//按照前缀查找
        int a = deleteFiles(list);
        System.out.println(a);
    }
}
